#include "LogicAdd.h"

LogicAdd& LogicAdd::getInstance() {

	if (_logicAdd == NULL) {
		_logicAdd = new LogicAdd;
	}

	return *_logicAdd;
}

LogicAdd::LogicAdd() {}

Display LogicAdd::addFloatingTask(string taskName) {
	
	string statusMessage;
	Data::DataFeedback dataFeedback;
	vector<Task> tasks;
	int currentTaskID;
	stringstream display;

	// task creation
	_task = Task(taskName, 0, Task::FLOATING, false, 0, not_a_date_time, not_a_date_time);

	// add into internal data
	dataFeedback = _data->executeAdd(_task);

	if( dataFeedback == Data::FAILURE ) {
		// log errors
	}

	currentTaskID = _data->getCurrentTaskID();

	_task.setTaskID(currentTaskID);
	
	if( dataFeedback == Data::SUCCESS ) {
		_data->getAll(tasks);
		_writer->write(tasks);
		display << ADD_SUCCESS_MESSAGE << taskName;
		statusMessage = display.str();
	} else {
		statusMessage = ADD_ERROR_MESSAGE;
	}

	// update UI's display
	_display = Display(statusMessage, tasks);

	return _display;
}

Display LogicAdd::addDeadlineTask(string taskName, ptime endTime) {
	
	string statusMessage;
	Data::DataFeedback dataFeedback;
	vector<Task> tasks;
	int currentTaskID;
	stringstream display;

	// task creation
	_task = Task(taskName, 0, Task::DEADLINE, false, 0, not_a_date_time, endTime);

	// add to internal data
	dataFeedback = _data->executeAdd(_task);

	if( dataFeedback == Data::FAILURE ) {
		// log errors
	}

	// update UI's display
	currentTaskID = _data->getCurrentTaskID();

	_task.setTaskID(currentTaskID);

	// return status message to UI
	if( dataFeedback == Data::SUCCESS ) {
		_data->getAll(tasks);
		_writer->write(tasks);
		display << ADD_SUCCESS_MESSAGE << taskName;
		display << ADD_DEADLINE_BY_CONNECTOR << endTime.date();
		statusMessage = display.str();
	} else {
		statusMessage = ADD_ERROR_MESSAGE;
	}

	// update UI's display
	_display = Display(statusMessage, tasks);

	return _display;
}

Display LogicAdd::addTimedTask(string taskName, ptime startTime, ptime endTime) {

	string statusMessage;
	Data::DataFeedback dataFeedback;
	vector<Task> tasks;
	bool clash;
	int currentTaskID;
	stringstream display;

	// task creation
	_task = Task(taskName, 0, Task::TIMED, false, 0, startTime, endTime);

	clash = isDateClash(startTime, endTime);

	// add to internal data
	dataFeedback = _data->executeAdd(_task);

	if( dataFeedback == Data::FAILURE ) {
		// log errors
	}

	// update UI's display
	currentTaskID = _data->getCurrentTaskID();
	_task.setTaskID(currentTaskID);

	// return status message to UI
	if( dataFeedback == Data::SUCCESS ) {
		_data->getAll(tasks);
		_writer->write(tasks);

		display << ADD_SUCCESS_MESSAGE << taskName;
		display << ADD_TIMED_FROM_CONNECTOR << startTime.date();
		display << ADD_TIMED_TO_CONNECTOR << endTime.date();
		if( clash ) {
			display << ADD_ERROR_CLASH_MESSAGE;
		}

		statusMessage = display.str();
	}

	// update UI's display
	_display = Display(statusMessage, tasks);

	return _display;
}

// returns true if clash
// returns false if no clash
bool LogicAdd::isDateClash(ptime startTime, ptime endTime) {

	bool isClash;
	string taskName;
	Data::DataFeedback dataFeedback;
	vector<Task> tasks;

	isClash = false;

	dataFeedback = _data->getAll(tasks);

	for( unsigned int i=0; i<tasks.size(); i++ ) {
		if( tasks[i].getTaskType() != Task::FLOATING ) {
			if( tasks[i].getEndDateTime() > startTime
				&& tasks[i].getStartDateTime() <= endTime ) {
					isClash = true;
			}
		}
	}

	return isClash;
}

LogicAdd::ErrorAdd LogicAdd::isDateCorrectFormat(ptime startTime, ptime endTime) {
	ErrorAdd dateFormat;

	ptime currTime = second_clock::local_time();
	ptime notADateTime;

	if( currTime > startTime || currTime > endTime ) {
		dateFormat = ERROR_DATE_PAST;
	} else if( startTime > endTime ) {
		if( startTime == notADateTime ) {
			dateFormat = NO_ERROR;
		} else {
			dateFormat = ERROR_START_END;
		}
	} else {
		dateFormat = NO_ERROR;
	}

	return dateFormat;
}

const string LogicAdd::ADD_SUCCESS_MESSAGE = "Task Added: ";

const string LogicAdd::ADD_DEADLINE_BY_CONNECTOR = " By ";
const string LogicAdd::ADD_TIMED_FROM_CONNECTOR = " From ";
const string LogicAdd::ADD_TIMED_TO_CONNECTOR = " To ";

const string LogicAdd::ADD_ERROR_MESSAGE = "Unable To Add";
const string LogicAdd::ADD_EXIST_ERROR_MESSAGE = "Task Already Exist";
const string LogicAdd::ADD_ERROR_CLASH_MESSAGE = " [CLASH]";
const string LogicAdd::ADD_DATE_PAST_ERROR_MESSAGE = "Past Date";
const string LogicAdd::ADD_DATE_START_END_ERROR_MESSAGE = "Start Date Earlier";

LogicAdd* LogicAdd::_logicAdd = NULL;